package com.example.blogdesign.Service.Impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.blogdesign.Entity.User;
import com.example.blogdesign.Entity.UserInfo;
import com.example.blogdesign.Mapper.UserMapper;

import com.example.blogdesign.Service.IUserInfoService;
import com.example.blogdesign.Service.IUserService;
import com.example.blogdesign.dto.LoginFormDTO;
import com.example.blogdesign.dto.RegisterDTO;
import com.example.blogdesign.dto.Result;
import com.example.blogdesign.dto.UserDTO;
import com.example.blogdesign.utils.RegexUtils;
import com.example.blogdesign.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.example.blogdesign.utils.PasswordEncoder.encode;
import static com.example.blogdesign.utils.PasswordEncoder.matches;
import static com.example.blogdesign.utils.RedisConstants.*;
import static com.example.blogdesign.utils.SystemConstants.USER_NICK_NAME_PREFIX;


@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {


    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IUserInfoService userInfoService;

    @Override
    public Result<?> sendCode(String phone) {
        //手机号校验
        if (RegexUtils.isPhoneInvalid(phone)) {
            //不符合，返回错误信息
            return Result.fail("手机号格式有误");
        }
        //符合，发送验证码
        String code = RandomUtil.randomNumbers(6);
        //保存到redis
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY+phone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);
        //发送验证码
        log.debug("验证码：{}",code);
        return Result.ok();
    }

    //登录
    @Override
    public Result<Object> login(LoginFormDTO loginForm) {
        //校验手机号
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)){
            return Result.fail("手机号格式错误");
        }
        //验证一致
        User user = query().eq("phone", phone).one();
        //判断是否存在
        if (user == null) {
            return Result.fail("尚未注册,请先注册");
        }
        if ((loginForm.getCode()==null || loginForm.getCode().equals(""))&&(loginForm.getPassword()==null||loginForm.getPassword().equals(""))){
            return Result.fail("错误");
        }
        //验证码为空，用密码登录
        if (loginForm.getCode()==null || loginForm.getCode().equals("")){
            Boolean isSuccess = matches(user.getPassword(), loginForm.getPassword());
            if (!isSuccess){
                return Result.fail("密码错误");
            }
            String token = saveInRedis(user);
            return Result.ok((Object) token);
        }
        if (loginForm.getPassword()==null||loginForm.getPassword().equals("")){
            //校验验证码
            if (RegexUtils.isCodeInvalid(loginForm.getCode())){
                return Result.fail("验证码格式有误");
            }
            Object code = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY+phone);
            String loginFormCode = loginForm.getCode();
            if (code==null||!code.toString().equals(loginFormCode)){
                return Result.fail("验证码错误");
            }
            String token = saveInRedis(user);
            return Result.ok((Object) token);
        }
        else {
            return Result.fail("");
        }
    }


    //登录后保存用户到redis
    public String saveInRedis(User user){
        //随机生成token
        String token = UUID.randomUUID().toString(true);
        //对象转为hash
        UserDTO userDTO= BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),
                CopyOptions.create().setIgnoreNullValue(true).
                        setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));
        //存到redis
        String tokenKey =LOGIN_USER_KEY+token;
        stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
        stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);
        return token;
    }


    //注册
    @Transactional
    @Override
    public Result<?> register(RegisterDTO registerDTO) {
        if (!registerDTO.getConfirm_password().equals(registerDTO.getPassword())){
            return Result.fail("两次密码不一致");
        }
        String phone = registerDTO.getPhone();
        User one = query().eq("phone", phone).one();
        if (one!=null){
            return Result.fail("你已注册,无需重复注册");
        }
        User user=new User();
        user.setPhone(phone);
        String password = registerDTO.getPassword();
        String encode = encode(password);
        user.setPassword(encode);
        user.setNickName(USER_NICK_NAME_PREFIX+RandomUtil.randomString(10));
        save(user);
        UserInfo userInfo = BeanUtil.copyProperties(user, UserInfo.class);
        userInfo.setUserId(user.getId());
        userInfoService.save(userInfo);
        return Result.ok("注册成功");
    }


    @Override
    public Result<?> logout(String token) {
        UserDTO user = UserHolder.getUser();
        if (user==null){
            return Result.fail("尚未登录");
        }
        String key=LOGIN_USER_KEY+token;
        stringRedisTemplate.delete(key);
        UserHolder.removeUser();
        return Result.ok();
    }



    @Override
    public Result<UserDTO> queryUserById(String userId) {
        User user = query().eq("id", userId).one();
        if (user==null){
            return Result.ok("无该用户");
        }
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        return Result.ok(userDTO);
    }

}

